import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class Student {
    //私有属性name
    private String name = "bit";
    //公有属性age
    public int age = 18;
    //不带参数的构造⽅法
    public Student(){
        System.out.println("Student()");
    }
    private Student(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println("Student(String,name)");
    }
    private void eat(){
        System.out.println("i am eat");
    }
    public void sleep(){
        System.out.println("i am pig");
    }
    private void function(String str) {
        System.out.println(str);
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class TestDemo {
    public static void main1(String[] args) {
        /*
        1.通过getClass获取Class对象
        */
        Student s = new Student();
        Class c1 = s.getClass();
        /*
        2.直接通过 类名.class 的⽅式得到,该⽅法最为安全可靠，程序性能更⾼
        这说明任何⼀个类都有⼀个隐含的静态成员变量 class
        */
        Class c2 = Student.class;
        /*
        3、通过 Class 对象的 forName() 静态⽅法来获取，⽤的最多，
        但可能抛出 ClassNotFoundException 异常
        */
        Class c3 = null;
        try {
            //注意这⾥是类的全路径，如果有包需要加包的路径
            c3 = Class.forName("Student");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //⼀个类在 JVM 中只会有⼀个 Class 实例,即我们对上⾯获取的
        //c1,c2,c3进⾏ equals ⽐较，发现都是true
        System.out.println(c1.equals(c2));
        System.out.println(c1.equals(c3));
        System.out.println(c2.equals(c3));
    }

    public static void main(String[] args)  {
        reflectNewInstance();
        reflectPrivateConstructor();
        reflectPrivateField();
        reflectPrivateMethod();
    }

    public static void reflectNewInstance() {
        try {
            //这里需要确保 Student 类在类路径中可用，否则会抛出 ClassNotFoundException。
            Class<?> classStudent = Class.forName("Student");
            //如果 Student 类没有无参构造方法，或者构造方法是私有的，会抛出异常（如 InstantiationException 或 IllegalAccessException）
            Object objectStudent = classStudent.newInstance();
            //如果类型不匹配，可能抛出 ClassCastException。
            Student student = (Student) objectStudent;
            System.out.println("获得学⽣对象：" + student);
            //通过 catch (Exception ex) 捕获，实际上可以处理所有继承自 Exception 的异常
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 反射私有的构造⽅法 屏蔽内容为获得公有的构造⽅法
    public static void reflectPrivateConstructor() {
        try{
        Class<?> classStudent = Class.forName("Student");
        ////注意传⼊对应的参数
        Constructor<?> declaredConstructorStudent = classStudent.getDeclaredConstructor(String.class, int.class);
        //Constructor<?> declaredConstructorStudent =
        classStudent.getConstructor();
        //设置为true后可修改访问权限
        declaredConstructorStudent.setAccessible(true);
        Object objectStudent = declaredConstructorStudent.newInstance("rjw", 15);
        //Object objectStudent = declaredConstructorStudent.newInstance();
        Student student = (Student) objectStudent;
        System.out.println("获得私有构造哈数且修改姓名和年龄：" + student);
        } catch(Exception ex){
        ex.printStackTrace();
        }

    }
    // 反射私有属性
    public static void reflectPrivateField() {
        try {
            Class<?> classStudent = Class.forName("Student");
            Field field = classStudent.getDeclaredField("name");
            //设置私有字段可访问，即使该字段是 private 的，也可以通过反射修改和访问它的值。
            field.setAccessible(true);
            //可以修改该属性的值
            Object objectStudent = classStudent.newInstance();
            Student student = (Student) objectStudent;
            field.set(student,"⼩明");
            String name = (String) field.get(student);
            System.out.println("反射私有属性修改了name："+ name);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 反射私有⽅法
    public static void reflectPrivateMethod() {
        try {
            Class<?> classStudent = Class.forName("Student");
            Method methodStudent = classStudent.getDeclaredMethod("function",String.class);
            System.out.println("私有⽅法的⽅法名为："+methodStudent.getName());
            //私有的⼀般都要加
            methodStudent.setAccessible(true);
            Object objectStudent = classStudent.newInstance();
            Student student = (Student) objectStudent;
            methodStudent.invoke(student,"我是给私有的function函数传的参数");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

}

